<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Kitchen Sink | Cypress Example">
  <meta name="author" content="Cypress.io">
  <meta name="copyright" content="Cypress.io, Inc">

  <title>Cypress.io: Kitchen Sink</title>

  <link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
  <link rel="stylesheet" href="/assets/css/vendor/bootstrap.min.css">
  <link rel="stylesheet" href="/assets/css/vendor/fira.css">
  <link rel="stylesheet" href="/assets/css/styles.css">
</head>

<body>
  <nav class="navbar navbar-inverse">
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar">
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="/">cypress.io</a>
      </div>
      <div id="navbar" class="navbar-collapse collapse">
        <ul class="nav navbar-nav">
          <li class="active" class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">Commands <span class="caret"></span></a>
            <ul class="dropdown-menu">
              <li><a href="/commands/querying">Querying</a></li>
              <li><a href="/commands/traversal">Traversal</a></li>
              <li><a href="/commands/actions">Actions</a></li>
              <li><a href="/commands/window">Window</a></li>
              <li><a href="/commands/viewport">Viewport</a></li>
              <li><a href="/commands/location">Location</a></li>
              <li><a href="/commands/navigation">Navigation</a></li>
              <li><a href="/commands/assertions">Assertions</a></li>
              <li><a href="/commands/misc">Misc</a></li>
              <li><a href="/commands/connectors">Connectors</a></li>
              <li><a href="/commands/aliasing">Aliasing</a></li>
              <li><a href="/commands/waiting">Waiting</a></li>
              <li class="active"><a href="/commands/network-requests">Network Requests</a></li>
              <li><a href="/commands/files">Files</a></li>
              <li><a href="/commands/local-storage">Local Storage</a></li>
              <li><a href="/commands/cookies">Cookies</a></li>
              <li><a href="/commands/spies-stubs-clocks">Spies, Stubs &amp; Clocks</a></li>
            </ul>
          </li>
          <li><a href="/utilities">Utilities</a></li>
          <li><a href="/cypress-api">Cypress API</a></li>
        </ul>
        <ul class="nav navbar-nav pull-right">
          <li><a href="https://github.com/cypress-io/cypress-example-kitchensink">GitHub</a></li>
        </ul>
      </div>
    </div>
  </nav>

  <div class="banner">
    <div class="container">
      <h1>Network Requests</h1>
      <p>Examples of handling AJAX or XHR requests in Cypress, for a full reference of commands, go to <a href="https://on.cypress.io/api" target="_blank">docs.cypress.io</a>
      </p>
    </div>
  </div>
  <div class="container content-container">
    <div id="network-requests">
      <div class="row">

        <div class="col-xs-7">
          <h4 id="server"><a href="https://on.cypress.io/server">cy.server()</a></h4>
          <p>To control the behavior of network requests and responses, use the <a href="https://on.cypress.io/server"><code>cy.server()</code></a> command.</p>
          <pre><code class="javascript">cy.server().should((server) => {
  // the default options on server
  // you can override any of these options
  expect(server.delay).to.eq(0)
  expect(server.method).to.eq('GET')
  expect(server.status).to.eq(200)
  expect(server.headers).to.be.null
  expect(server.response).to.be.null
  expect(server.onRequest).to.be.undefined
  expect(server.onResponse).to.be.undefined
  expect(server.onAbort).to.be.undefined

  // These options control the server behavior
  // affecting all requests

  // pass false to disable existing route stubs
  expect(server.enable).to.be.true
  // forces requests that don't match your routes to 404
  expect(server.force404).to.be.false
  // whitelists requests from ever being logged or stubbed
  expect(server.whitelist).to.be.a('function')
})

cy.server({
  method: 'POST',
  delay: 1000,
  status: 422,
  response: {},
})</code></pre>
    </div>
        <div class="col-xs-5">
        </div>

        <div class="col-xs-12"><hr></div>

        <div class="col-xs-7">
          <h4 id="request"><a href="https://on.cypress.io/request">cy.request()</a></h4>
          <p>To make an XHR request, use the <a href="https://on.cypress.io/request"><code>cy.request()</code></a> command.</p>
          <pre><code class="javascript">cy.request('https://jsonplaceholder.cypress.io/comments')
  .should((response) => {
    expect(response.status).to.eq(200)
    expect(response.body).to.have.length(500)
    expect(response).to.have.property('headers')
    expect(response).to.have.property('duration')
  })</code></pre>
          <p>A request can pass the response data to the next request.</p>
          <pre><code class="javascript">// first, let's find out the userId of the first user we have
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
  .its('body.0') // yields the first element of the returned list
  .then((user) => {
    expect(user).property('id').to.be.a('number')
    // make a new post on behalf of the user
    cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
      userId: user.id,
      title: 'Cypress Test Runner',
      body: 'Fast, easy and reliable testing for anything that runs in a browser.',
    })
  })
  // note that the value here is the returned value of the 2nd request
  // which is the new post object
  .then((response) => {
    expect(response).property('status').to.equal(201) // new entity created
    expect(response).property('body').to.contain({
      title: 'Cypress Test Runner',
    })
    // we don't know the exact post id - only that it will be > 100
    // since JSONPlaceholder has built-in 100 posts
    expect(response.body).property('id').to.be.a('number')
      .and.to.be.gt(100)
    // we don't know the user id here - since it was in above closure
    // so in this test just confirm that the property is there
    expect(response.body).property('userId').to.be.a('number')
  })</code></pre>

        <p>A good idea is to save the response data to be used later in the shared test context.</p>
        <pre><code class="javascript">cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
  .its('body.0') // yields the first element of the returned list
  .as('user') // saves the object in the test context
  .then(function () {
    // NOTE 👀
    //  By the time this callback runs the "as('user')" command
    //  has saved the user object in the test context.
    //  To access the test context we need to use
    //  the "function () { ... }" callback form,
    //  otherwise "this" points at a wrong or undefined object!
    cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
      userId: this.user.id,
      title: 'Cypress Test Runner',
      body: 'Fast, easy and reliable testing for anything that runs in a browser.',
    })
    .its('body').as('post') // save the new post from the response
  })
  .then(function () {
    // When this callback runs, both "cy.request" API commands have finished
    // and the test context has "user" and "post" objects set.
    // Let's verify them.
    expect(this.post, 'post has the right user id')
      .property('userId').to.equal(this.user.id)
  })</code></pre>
        </div>

        <div class="col-xs-5">
        </div>

        <div class="col-xs-12"><hr></div>

        <div class="col-xs-7">
          <h4 id="route"><a href="https://on.cypress.io/route">cy.route()</a></h4>
          <p>To route responses to matching requests, use the <a href="https://on.cypress.io/route"><code>cy.route()</code></a> command.</p>
          <pre><code class="javascript">let message = 'whoa, this comment does not exist'
cy.server()

// Listen to GET to comments/1
cy.route('GET', 'comments/*').as('getComment')

// we have code that gets a comment when
// the button is clicked in scripts.js
cy.get('.network-btn').click()

// https://on.cypress.io/wait
cy.wait('@getComment').its('status').should('eq', 200)

// Listen to POST to comments
cy.route('POST', '/comments').as('postComment')

// we have code that posts a comment when
// the button is clicked in scripts.js
cy.get('.network-post').click()
cy.wait('@postComment')

// get the route
cy.get('@postComment').should((xhr) => {
  expect(xhr.requestBody).to.include('email')
  expect(xhr.requestHeaders).to.have.property('Content-Type')
  expect(xhr.responseBody).to.have.property('name', 'Using POST in cy.route()')
})

// Stub a response to PUT comments/ ****
cy.route({
  method: 'PUT',
  url: 'comments/*',
  status: 404,
  response: { error: message },
  delay: 500,
}).as('putComment')

// we have code that puts a comment when
// the button is clicked in scripts.js
cy.get('.network-put').click()

cy.wait('@putComment')

// our 404 statusCode logic in scripts.js executed
cy.get('.network-put-comment').should('contain', message)</code></pre>
        </div>
        <div class="col-xs-5">
          <div class="well">
            <button class="network-btn btn btn-primary">Get Comment</button>
            <div class="network-comment"></div>
            <button class="network-post btn btn-success">Post Comment</button>
            <div class="network-post-comment"></div>
            <button class="network-put btn btn-warning">Update Comment</button>
            <div class="network-put-comment"></div>
          </div>
        </div>

        <div class="col-xs-12"><hr></div>

      </div>
    </div>
  </div>

  <script src="/assets/js/vendor/jquery-1.12.0.min.js"></script>
  <script src="/assets/js/vendor/bootstrap.min.js"></script>
  <script src="/assets/js/vendor/highlight.pack.js"></script>
  <script src="/assets/js/scripts.js"></script>
</body>
</html>
